package info.xmlprint.ui.innerlink;

import info.xmlprint.core.innerlink.InnerLink;
import info.xmlprint.core.mapping.ElementPath;
import info.xmlprint.core.mapping.ElementPathNode;
import info.xmlprint.core.project.PrintProject;
import info.xmlprint.core.xml.PAttribut;
import info.xmlprint.core.xml.PElement;
import info.xmlprint.core.xml.PElementGroup;
import info.xmlprint.ui.message.GuiMessages;
import info.xmlprint.ui.widgets.EditElementPostionComposite;
import info.xmlprint.ui.widgets.IObserverControl;
import info.xmlprint.ui.widgets.ISetupComposite;
import info.xmlprint.ui.widgets.ISubjectControl;
import info.xmlprint.util.XmlUtil;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;

public class InnerLinkComposite extends Composite implements ISubjectControl,
		ISetupComposite {
	private InnerLinkComposite _this = this;

	private String[] elementNames;

	private InnerLink innerLink;

	private List<IObserverControl> observerList = new ArrayList<IObserverControl>();

	private PElementGroup pElementGroup;

	private PrintProject printProject;

	private Combo sourceElementCombo, sourceAttributCombo, targetElementCombo,
			targetAttributCombo;

	private HashMap<String, ElementPath> sourceEPathMap;

	private EditElementPostionComposite sourcePositionComp, targetPositionComp;
	private HashMap<String, ElementPath> targetEPathMap;

	public InnerLinkComposite(Composite parent, int style) {
		super(parent, style);
		this.setLayout(new GridLayout());
		createControls();
	}

	private void comboSelectAction(Combo elementCombo, Combo attributCombo,
			EditElementPostionComposite comp,
			HashMap<String, ElementPath> ePathMap) {
		String selection = elementCombo.getText();
		if (selection == null) {
			return;
		}
		PElement element = pElementGroup.getElement(selection);
		fillPostionComposite(comp, selection, ePathMap);
		attributCombo.removeAll();
		for (PAttribut a : element.getAttributs()) {
			attributCombo.add(a.getName());
		}
		attributCombo.getParent().layout();// fixed layout problem in
		// linux: combo 
	}

	private void createControls() {
		this.setLayout(new GridLayout(3, false));
		Group sourceGroup = new Group(this, SWT.NONE);
		sourceGroup.setText("Select Source Element");
		sourceGroup.setLayout(new GridLayout(2, false));
		sourceGroup.setLayoutData(new GridData(GridData.FILL_BOTH));
		new Label(sourceGroup, SWT.NONE).setText("Element:");
		sourceElementCombo = new Combo(sourceGroup, SWT.NONE);
		sourceElementCombo.setLayoutData(new GridData());
		sourceElementCombo.addListener(SWT.Selection, new Listener() {
			@Override
			public void handleEvent(Event event) {
				comboSelectAction(sourceElementCombo, sourceAttributCombo,
						sourcePositionComp, sourceEPathMap);
			}
		});
		sourcePositionComp = new EditElementPostionComposite(sourceGroup,
				SWT.NONE);
		GridData gd1 = new GridData(GridData.FILL_BOTH);
		gd1.horizontalSpan = 2;
		sourcePositionComp.setLayoutData(gd1);

		new Label(this, SWT.NONE).setText(">>");

		Group targetGroup = new Group(this, SWT.NONE);
		targetGroup.setText("Select Target Element");
		targetGroup.setLayout(new GridLayout(2, false));
		targetGroup.setLayoutData(new GridData(GridData.FILL_BOTH));
		new Label(targetGroup, SWT.NONE).setText("Elememnt:");
		targetElementCombo = new Combo(targetGroup, SWT.NONE);
		targetElementCombo.setLayoutData(new GridData());
		targetElementCombo.addListener(SWT.Selection, new Listener() {
			@Override
			public void handleEvent(Event event) {
				comboSelectAction(targetElementCombo, targetAttributCombo,
						targetPositionComp, targetEPathMap);
			}
		});
		targetPositionComp = new EditElementPostionComposite(targetGroup,
				SWT.NONE);
		GridData gd2 = new GridData(GridData.FILL_BOTH);
		gd2.horizontalSpan = 2;
		targetPositionComp.setLayoutData(gd2);

		Group sourceKeyGroup = new Group(this, SWT.NONE);
		sourceKeyGroup.setText("Select Key Attribut");
		sourceKeyGroup.setLayout(new GridLayout(1, false));
		sourceAttributCombo = new Combo(sourceKeyGroup, SWT.NONE);
		sourceAttributCombo.setLayoutData(new GridData());

		new Label(this, SWT.CENTER).setText(" =");

		Group targetKeyGroup = new Group(this, SWT.NONE);
		targetKeyGroup.setText("Select Key Attribut");
		targetKeyGroup.setLayout(new GridLayout(1, false));
		targetAttributCombo = new Combo(targetKeyGroup, SWT.NONE);
		targetAttributCombo.setLayoutData(new GridData());

		Composite buttonComp = new Composite(this, SWT.NONE);
		GridData gd = new GridData();
		gd.verticalIndent = 20;
		gd.horizontalSpan = 6;
		gd.horizontalAlignment = GridData.END;
		buttonComp.setLayoutData(gd);

		RowLayout rowLayout = new RowLayout();
		rowLayout.pack = false;
		rowLayout.spacing = 15;
		buttonComp.setLayout(rowLayout);

		// save
		Button okButton = new Button(buttonComp, SWT.NONE);
		okButton.setText(GuiMessages.General_Gui_Okay);
		okButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				if (updateInput()) {
					_this.getShell().close();
					notifyObservers();
				}
			}
		});

		Button cancelButton = new Button(buttonComp, SWT.NONE);
		cancelButton.setText(GuiMessages.General_Gui_Cancel);
		cancelButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				_this.getShell().close();
			}
		});

		this.pack();

	}

	private void fillControls() {
		resetControls();
		List<String> list = new ArrayList<String>();

		for (PElement pe : pElementGroup.getElements()) {
			if (pe.getAttributCount() > 0) {// only element that hat attribute
				list.add(pe.getName());
			}
		}
		if (!list.isEmpty()) {
			elementNames = list.toArray(new String[list.size()]);
			sourceElementCombo.setItems(elementNames);
			targetElementCombo.setItems(elementNames);
			sourceElementCombo.getParent().layout();// fixed layout problem 
													// linux: combo
			targetElementCombo.getParent().layout();// fixed layout problem in
													// linux: combo
		}

		if (innerLink != null) {
			String mainNamespacePrefix = printProject.getPElementGroup()
					.getMainNamespacePrefix();
			String sourceElementName = innerLink.getValueOf("source-element");
			sourceElementCombo.setText(sourceElementName);
			sourceAttributCombo
					.setText(innerLink.getValueOf("source-attribut"));
			// get elementPaht from xml input
			ElementPath sourEPath = XmlUtil.string2ElementPath(
					innerLink.getValueOf("source-epath"),
					innerLink.getValueOf("source-epath-index"),
					mainNamespacePrefix);
			sourceEPathMap.put(sourceElementName, sourEPath);
			fillPostionComposite(sourcePositionComp, sourceElementName,
					sourceEPathMap);

			String targetElementName = innerLink.getValueOf("target-element");
			targetElementCombo.setText(targetElementName);
			targetAttributCombo
					.setText(innerLink.getValueOf("target-attribut"));
			// get elementPaht from xml input
			ElementPath tarEPath = XmlUtil.string2ElementPath(
					innerLink.getValueOf("target-epath"),
					innerLink.getValueOf("target-epath-index"),
					mainNamespacePrefix);
			targetEPathMap.put(targetElementName, tarEPath);
			fillPostionComposite(targetPositionComp, targetElementName,
					targetEPathMap);
		}
	}

	private void fillPostionComposite(
			EditElementPostionComposite ePositionComp, PElement pElement,
			HashMap<String, ElementPath> ePathMap) {
		ElementPath ePath;
		String name = pElement.getName();
		if (ePathMap.get(name) == null) {
			ePath = new ElementPath();
			ElementPathNode epn = new ElementPathNode(pElement);
			ePath.addNode(null, epn);
			ePath.setcurrPathNode(epn);
			ePathMap.put(name, ePath);
		} else {
			ePath = ePathMap.get(name);
		}
		ePositionComp.setInput(ePath);
	}

	private void fillPostionComposite(EditElementPostionComposite comp,
			String name, HashMap<String, ElementPath> ePathMap) {
		PElement element = pElementGroup.getElement(name);
		fillPostionComposite(comp, element, ePathMap);
	}

	@Override
	public void notifyObservers() {
		for (IObserverControl o : observerList) {
			o.updateControl();
		}
	}

	@Override
	public void registerObserver(IObserverControl observer) {
		observerList.add(observer);
	}

	@Override
	public void removeObserver(IObserverControl observer) {
		observerList.remove(observer);
	}

	private void resetControls() {
		sourceElementCombo.setText("");
		sourceAttributCombo.setText("");
		sourcePositionComp.setInput(null);
		targetElementCombo.setText("");
		targetAttributCombo.setText("");
		targetPositionComp.setInput(null);
	}

	public void setInput(InnerLink innerlink) {
		this.innerLink = innerlink;
		sourceEPathMap = new HashMap<String, ElementPath>();
		targetEPathMap = new HashMap<String, ElementPath>();
		fillControls();
	}

	@Override
	public void setPrintProject(PrintProject pProject) {
		printProject = pProject;
		pElementGroup = printProject.getPElementGroup();
		sourcePositionComp.setPrintProject(pProject);
		targetPositionComp.setPrintProject(pProject);
	}

	private boolean updateInput() {
		// validate
		String sourElem = sourceElementCombo.getText();
		String sourAttr = sourceAttributCombo.getText();
		String tarElem = targetElementCombo.getText();
		String targAttr = targetAttributCombo.getText();

		if (sourElem == null || sourAttr == null || tarElem == null
				|| targAttr == null || sourElem.isEmpty() || sourAttr.isEmpty()
				|| tarElem.isEmpty() || targAttr.isEmpty()) {
			MessageDialog.openError(null, "", "All fields must be filled");
			return false;
		}
		if (innerLink == null) {
			innerLink = new InnerLink();
			printProject.getInnerLinkGroup().add(innerLink);
		}

		innerLink.setElementValue("source-element", sourElem);
		innerLink.setElementValue("source-attribut", sourAttr);
		ElementPath sourPath = sourceEPathMap.get(sourElem);
		innerLink.setElementValue("source-epath", sourPath.getFullPathString());
		innerLink.setElementValue("source-epath-index", sourPath.getCurrIndex()
				+ "");

		innerLink.setElementValue("target-element", tarElem);
		innerLink.setElementValue("target-attribut", targAttr);
		ElementPath tarPath = targetEPathMap.get(tarElem);
		innerLink.setElementValue("target-epath", tarPath.getFullPathString());
		innerLink.setElementValue("target-epath-index", tarPath.getCurrIndex()
				+ "");
		return true;
	}
}
